﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ProgramCat.FiddlerExtension.Core.Utils.Crypto
{
    /// <summary>
    /// Description of CryptoGraphy.
    /// </summary>
    public class RC4Crypt : Singleton<RC4Crypt>
    {
        byte[] S;
        byte[] T;
        byte[] K = new byte[0];
        byte[] k ;
        private RC4Crypt() {
        
        }
        public byte[] Key
        {
            get
            {
                return K;
            }
            set
            {
                K = value;
            }
        }
        //初始化状态向量S和临时向量T，供keyStream方法调用
        void initial()
        {
            if (this.S == null || this.T == null)
            {
                this.S = new byte[256];
                this.T = new byte[256];
            }
            for (int i = 0; i < 256; ++i)
            {
                this.S[i] = (byte)i;
                this.T[i] = this.K[i % this.K.Length];
            }
        }
        //初始排列状态向量S，供keyStream方法调用
        void ranges()
        {
            int j = 0;
            for (int i = 0; i < 256; ++i)
            {
                j = (j + S[i] + T[i]) & 0xff;
                this.S[i] = (byte)((this.S[i] + this.S[j]) & 0xff);
                this.S[j] = (byte)((this.S[i] - this.S[j]) & 0xff);
                this.S[i] = (byte)((this.S[i] - this.S[j]) & 0xff);
            }
        }
        //生成密钥流
        //len:明文为len个字节
        void keyStream(int len)
        {
            initial();
            ranges();
            int i = 0, j = 0, t = 0;
            k = new byte[len];
            for (int r = 0; r < len; r++)
            {
                i = (i + 1) & 0xff;
                j = (j + S[i]) & 0xff;

                this.S[i] = (byte)((this.S[i] + this.S[j]) & 0xff);
                this.S[j] = (byte)((this.S[i] - this.S[j]) & 0xff);
                this.S[i] = (byte)((this.S[i] - this.S[j]) & 0xff);

                t = (this.S[i] + this.S[j]) & 0xff;
                this.k[r] = this.S[t];
            }
        }

        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public byte[] EncryptByte(byte[] data)
        {
            //生产密匙流
            keyStream(data.Length);
            for (int i = 0; i < data.Length; i++)
            {
                k[i] = (byte)(data[i] ^ k[i]);
            }
            return k;
        }
        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public byte[] DecryptByte(byte[] data)
        {
            return EncryptByte(data);
        }

    }
}
